package com.winter.boot.config;

import com.winter.boot.annotation.Resource;
import com.winter.boot.aop.BeanProxyFactory;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DefaultBeanFactory implements BeanFactory {

    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
    private volatile Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    private final Map<String, Object> singleMap = new ConcurrentHashMap<>(256);//一级缓存 存放代理对象
    private final BeanProxyFactory beanProxyFactory = new BeanProxyFactory();
    public void createBean(String beanName, RootBeanDefinition beanDefinition) {
        Object beanClass = beanDefinition.getBeanClass();
        beanDefinitionMap.putIfAbsent(beanName, beanDefinition);
        beanDefinitionNames.add(beanName);
    }

    public Object getBean(String beanName) {
        return this.beanDefinitionMap.get(beanName).getBeanClass();
    }

    @Override
    public List<Class<?>> getParams(String beanName) {
        return this.beanDefinitionMap.get(beanName).getParams();
    }

    @Override
    public void registerBeanPostProcessors() throws IllegalAccessException {
        for (String beanDefinitionName : this.beanDefinitionNames) {
            Object bean = this.getBean(beanDefinitionName);
            Class<?> beanClass = bean.getClass();
            Field[] fields = beanClass.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                Resource resource = field.getAnnotation(Resource.class);
                if (resource != null) {
                    Class<?> type = field.getType();
                    Object proxy = singleMap.get(type.getTypeName());
                    if(proxy == null){
                        BeanDefinition fieldBean = beanDefinitionMap.get(type.getTypeName());
                        proxy = this.beanProxyFactory.createBean(fieldBean.getBeanClass());
                        singleMap.put(type.getTypeName(), proxy);
                    }
                   field.set(bean, proxy);
                }
            }
        }

    }

}
